package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.repository.IStrategyTemplateRepository;
import cn.wolfcode.luowowo.search.service.IStrategySearchService;
import cn.wolfcode.luowowo.search.template.StrategyTemplate;
import cn.wolfcode.luowowo.search.vo.StatisVO;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.apache.lucene.search.BooleanQuery;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.TermsValuesSourceBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.Query;

import java.util.*;

@Service
public class StrategySearchServiceImpl implements IStrategySearchService {
    @Autowired
    private IStrategyTemplateRepository dao;
    @Autowired
    private ElasticsearchTemplate template;
    @Autowired
    private TransportClient client;

    public void createIndex() {
        template.createIndex(StrategyTemplate.class);
        template.getMapping(StrategyTemplate.class);
    }
    public void save(StrategyTemplate t) {
        dao.save(t);
    }


    @Override
    public Page<StrategyTemplate> queryStrategyByDestId(SearchQueryObject qo) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (qo.getDestId() != -1){
            boolQuery.must(QueryBuilders.termQuery("destId", qo.getDestId()));
        }
        return dao.search(boolQuery, qo.getPageableWithoutSort());
    }

    @Override
    public Page<StrategyTemplate> query(SearchQueryObject qo) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(qo.getType() == SearchQueryObject.CONDITION_TYPE_ABROAD){ //国外
            boolQuery.mustNot(QueryBuilders.matchQuery("countryId", qo.getTypeValue()));
        }else if(qo.getType() == SearchQueryObject.CONDITION_TYPE_UNABROAD){ //国内
            boolQuery.must(QueryBuilders.matchQuery("provinceId", qo.getTypeValue()));
        }else if(qo.getType() == SearchQueryObject.CONDITION_TYPE_THEME){ //主题
            boolQuery.must(QueryBuilders.matchQuery("themeId", qo.getTypeValue()));
        }
        Page<StrategyTemplate> page = dao.search(boolQuery, qo.getPageable());
        return page;
    }




    //根据分组查询条件查询对应的攻略数据
    public List<StatisVO> queryStrategyByCondition(int conditionType) {
        String idField = "";
        String nameField = "";
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(conditionType == SearchQueryObject.CONDITION_TYPE_ABROAD){ //国外
            idField = "countryId";  //分组字段
            nameField = "countryName"; //分组字段
            //查询条件
            boolQuery.mustNot(QueryBuilders.matchQuery("countryId", 1));
        }else if(conditionType == SearchQueryObject.CONDITION_TYPE_UNABROAD){ //国内
            idField = "provinceId";
            nameField = "provinceName";
            boolQuery.must(QueryBuilders.matchQuery("countryId", 1));
        }else if(conditionType == SearchQueryObject.CONDITION_TYPE_THEME){ //主题
            idField = "themeId";
            nameField = "themeName";
        }
        return this.statisGroup(idField, nameField, "conditionGroup", boolQuery);
    }

    //根据查询条件和分组条件查询攻略数据
    private List<StatisVO> statisGroup(String idField, String nameField, String groupName, QueryBuilder query){
        List<CompositeValuesSourceBuilder<?>> source = new ArrayList<>();
        //构建分组字段对象
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        idSource.field(idField); //分组字段
        idSource.missingBucket(true); //忽略不满足条件的bucket(查不出来或匹配不上的)
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        nameSource.field(nameField);
        nameSource.missingBucket(true);

        source.add(idSource);
        source.add(nameSource);
        //参数1: 分组的名称
        //参数2: 分组字段的集合
        CompositeAggregationBuilder builder = new CompositeAggregationBuilder(groupName, source);

        //获取查询请求对象, 设置索引
        SearchRequest request = new SearchRequest(StrategyTemplate.INDEX_NAME);
        //设置类型
        request.types(StrategyTemplate.TYPE_NAME);
        request.source(new SearchSourceBuilder()
                .aggregation(builder)
                .size(0)
                .query(query));
        //发起请求, 获取响应结果
        SearchResponse response = client.search(request).actionGet();

        //获取聚合查询分组对象
        CompositeAggregation compositeAggregation = response.getAggregations().get(groupName);
        List<? extends CompositeAggregation.Bucket> buckets = compositeAggregation.getBuckets();

        ArrayList<StatisVO> vos = new ArrayList<>();
        for (CompositeAggregation.Bucket bucket : buckets) {
            StatisVO vo = new StatisVO();
            Map<String, Object> key = bucket.getKey();
            vo.setId(Long.valueOf(key.get("id").toString()));
            vo.setName(key.get("name").toString());
            vo.setCount(bucket.getDocCount());
            vos.add(vo);
        }
        return vos;
    }

    //查询推荐的主题相关数据
    public List<Map<String, Object>> queryThemeCommends() {
        List<StatisVO> themeVos = this.statisGroup("themeId", "themeName", "themeGroup", QueryBuilders.boolQuery());
        //排序
        Collections.sort(themeVos, new Comparator<StatisVO>() {
            public int compare(StatisVO o1, StatisVO o2) {
                return o2.getCount().compareTo(o1.getCount());
            }
        });
        //获取排序前十的theme对象
        if (themeVos.size() > 10) {
            themeVos.subList(0, 10);
        }
        List<Map<String, Object>> list = new ArrayList<>();

        //查询每个主题下所有的攻略目的地
        for (StatisVO themeVo : themeVos) {
            HashMap<String, Object> map = new HashMap<>();
            List<StatisVO> destVos = queryDestByThemeId(themeVo.getId());
            map.put("themeVo", themeVo);
            map.put("destVOs", destVos);
            list.add(map);
        }
        return list;
    }

    private List<StatisVO> queryDestByThemeId(Long themeId) {
        //获取themeId=themeId的目的地对象数据的迭代器对象
        Iterable<StrategyTemplate> iterable = dao.search(QueryBuilders.termQuery("themeId", themeId));
        ArrayList<StatisVO> destVos = new ArrayList<>();
        //目的地名字集合, 用来去重
        ArrayList<String> names = new ArrayList<>();
        iterable.forEach(s -> {
            if (!names.contains(s.getDestName())) {
                StatisVO vo = new StatisVO();
                vo.setId(s.getDestId());
                vo.setName(s.getDestName());
                destVos.add(vo);
                names.add(s.getDestName());
            }
        });
        return destVos;
    }
}
